// pinning.cpp 
// Example program for Monte Carlo grain growth with particle pinning
// Questions/comments to gruberja@gmail.com (Jason Gruber)

#include "pinning.hpp"
#include <unistd.h>			// header library for running options.

using namespace MMSP;

int main(int argc, char* argv[])
{
	int opt;
	int dim=2;
	int loop=0;
	int intv=999999999;
	char* outName="pinning";
	char* inName;
	bool file_is = false;		// conditional parameter for an existing input file

	Init(argc,argv);	// initialization for running options.

    while((opt = getopt(argc, argv, "d:O:l:i:I:")) != -1)
    {
        switch(opt)
        {
            case 'd':		// dimension option (default value: 2)
            	dim = atoi(optarg);
                break;
            case 'O':		// output file name option (default: "pinning")
            	outName = optarg;
            	//std::cout<<outName;
                break;
            case 'l':		// loop value option (default value: 0)
            	loop = atoi(optarg);
            	//std::cout<<loop<<std::endl;
                break;
            case 'i':		// internal value option (default value: very large number)
            	intv = atoi(optarg);
            	//std::cout<<intv<<std::endl;
                break;
            case 'I':		// input file name option
            	inName = optarg;
            	file_is = true;
            	//std::cout<<intv<<std::endl;
                break;
        }
    }

    // command line error check
//	if (ii<1) {
//		std::cout<<"Usage: "<<argv[0]<<" dimension outputfile timesteps\n";
//		exit(-1);
//	}
	// read grid dimension
//	int dim = atoi(argv[1]);

	// 간격별로 중간 데이터 생성을 위한 정수 변수들
    int count=0;
	int quot=0;
	int rem=0;

	quot = loop / intv;		//간격별 구간을 나타내는 몫 값
	//std::cout<<quot<<std::endl;
	rem = loop % intv;		//마지막 잔여 구간을 나타내는 나머지 값
	//std::cout<<rem<<std::endl;

	// 간격별 생성되는 파일의 이름을 순서대로 명시하기 위한 문자열 변수 선언
	char buffer [2][50];

/*	MCgrid2D* grid = new MCgrid2D(400,400);
	for (int x=0; x<400; x++)
		for (int y=0; y<400; y++)
			(*grid)[x][y] = 1+rand()%(1000-1);
	// generate needle-shaped particles
	int length = 10;
	int particles = 200;
	for (int i=0; i<particles; i++) {
		int x = rand()%400;
		int y = rand()%400;
		for (int j=0; j<length; j++)
			(*grid)[x][(y+j)%400] = 0;
	}
	updateTest(grid,100);

	sprintf(buffer[1],"%s%d%s",outName,100,".asc");
	outputASCII((*grid),buffer[1]);

	delete grid;
	exit(1);
*/
	// ----------------------------------------------
	// Monte Carlo grain growth with particle pinning
	// ----------------------------------------------

	if (dim==2 && file_is==false) {
		// Generate a Grid Object
		int xmax = 400;
		int ymax = 200;

		MCgrid2D grid(xmax,ymax);

		// assign random spins to grid
		int Q = 1000;
		for (int x=0; x<xmax; x++)
			for (int y=0; y<ymax; y++)
				grid[x][y] = 1+rand()%(Q-1);
		// generate needle-shaped particles
		int length = 10;
		int particles = 100;
		for (int i=0; i<particles; i++) {
			int x = rand()%xmax;
			int y = rand()%ymax;
			for (int j=0; j<length; j++)
				grid[x][(y+j)%ymax] = 0;
		}

		// Grain Growth Simulation
		// 1. 주어진 간격크기를 가지고 몫 값(간격별 횟수)만큼 update 수행
		for (int i=0; i<quot; i++) {
			update(grid,intv);
			count = (i+1)*intv;
			sprintf(buffer[0],"%s%d%s",outName,count,".MC");
			sprintf(buffer[1],"%s%d%s",outName,count,".asc");
			output(grid,buffer[0]);
			outputASCII(grid,buffer[1]);
		}
		// 2. 몫 값의 배수로 수행이 위에서 끝나면, 나머지 잔여 구간(나머지 값) 만큼  update 수행
		if (rem != 0) {
			update(grid,rem);
			count += rem;
			sprintf(buffer[0],"%s%d%s",outName,count,".MC");
			sprintf(buffer[1],"%s%d%s",outName,count,".asc");
			output(grid,buffer[0]);
			outputASCII(grid,buffer[1]);
		}
	}

	if (dim==2 && file_is==true) {
		// Generate a Grid Object
		int xmax;
		int ymax;

		std::ifstream initGrid(inName);

		if (!initGrid)
		{
			std::cout<<"There is no input file."<<std::endl;
			exit(0);
		}

		initGrid>>buffer[0]; initGrid>>xmax;
		initGrid>>buffer[0]; initGrid>>ymax;
		initGrid>>buffer[0]; initGrid>>buffer[0];
		initGrid>>buffer[0]; initGrid>>buffer[0];
		initGrid>>buffer[0]; initGrid>>buffer[0];
		initGrid>>buffer[0]; initGrid>>buffer[0];

		// make Grid
		MCgrid2D grid(xmax,ymax);

		std::cout<<" Height of the input grid : "<<ymax<<std::endl;
		std::cout<<" Width of the input grid :  "<<xmax<<std::endl;


/*		for (int j=ymax; j>0; j--)
			for (int i=0; i<xmax; i++)
			{
				initGrid>>grid[j][i];
			}
*/
		for (int j=0; j<ymax; j++)
			for (int i=0; i<xmax; i++)
			{
				initGrid>>grid[i][j];
			}

		initGrid.close();

		sprintf(buffer[0],"%s%d%s",outName,count,".MC");
		sprintf(buffer[1],"%s%d%s",outName,count,".asc");
		output(grid,buffer[0]);
		outputASCII(grid,buffer[1]);
		// Grain Growth Simulation
		// 1. 주어진 간격크기를 가지고 몫 값(간격별 횟수)만큼 update 수행
		for (int i=0; i<quot; i++) {
			update(grid,intv);
			count = (i+1)*intv;
			sprintf(buffer[0],"%s%d%s",outName,count,".MC");
			sprintf(buffer[1],"%s%d%s",outName,count,".asc");
			output(grid,buffer[0]);
			outputASCII(grid,buffer[1]);
		}
		// 2. 몫 값의 배수로 수행이 위에서 끝나면, 나머지 잔여 구간(나머지 값) 만큼  update 수행
		if (rem != 0) {
			update(grid,rem);
			count += rem;
			sprintf(buffer[0],"%s%d%s",outName,count,".MC");
			sprintf(buffer[1],"%s%d%s",outName,count,".asc");
			output(grid,buffer[0]);
			outputASCII(grid,buffer[1]);
		}
	}

	if (dim==3) {
		// generate a grid object
		int xmax = 100;
		int ymax = 100;
		int zmax = 100;

		MCgrid3D grid(xmax,ymax,zmax);

		// assign random spins to grid
		int Q = 1000;
		for (int x=0; x<xmax; x++)
			for (int y=0; y<ymax; y++)
				for (int z=0; z<zmax; z++)
					grid[x][y][z] = 1+rand()%(Q-1);

		// generate needle-shaped particles
		int length = 10;
		int particles = 1000;
		for (int i=0; i<particles; i++) {
			int x = rand()%xmax;
			int y = rand()%ymax;
			int z = rand()%zmax;
			for (int j=0; j<length; j++)
				grid[x][y][(z+j)%zmax] = 0;
		}

		// grain growth simulation
		update(grid,atoi(argv[3]));

		// output the grid to a file
		output(grid,argv[2]);
	}

	Finalize();
}
